24.5 The raise Statement
To trigger
exceptions
explicitly, you code raise statements. Their
general form is simple—the word raise,
optionally followed by both the name of the exception to be raised
and an extra data item to pass with the exception:
raise <name> # Manually trigger an exception.
raise <name>, <data> # Pass extra data to catcher too.
raise # Reraise the most recent exception.
The second form allows you to pass an extra data item along with the
exception, to provide details for the handler. In the
raise, the data is listed after the exception
name; back in the try statement, the data is
obtained by including a variable to receive it. For instance, in
except name,X:, X will be
assigned the extra data item listed at the raise.
The third raise form simply reraises the current exception;
it's handy if you want to propagate an exception
you've caught to another handler.
So what's an exception name? It might be the name of
a built-in exception from the built-in scope (e.g.,
IndexError), or the name of an arbitrary string
object you've assigned in your program. It can also
reference a user-defined class or class instance—a possibility
that further generalizes raise statement formats.
We'll postpone the details of this generalization
until after we have a chance to study class exceptions in the next
chapter.
Regardless of how you name exceptions, they are always identified by
normal objects, and at most one is active at any given time. Once
caught by an except clause anywhere in the
program, an exception dies (won't propagate to
another try), unless reraised by another
raise statement or error.
24.5.1 Example: Raising and Catching User-Defined Exceptions
Python programs can trigger both
built-in and user-defined
exceptions, using the raise statement. In their
simplest form, user-defined exceptions are string objects, like the
one that variable MyBad is assigned to in the
following:
MyBad = "oops"
def stuff( ):
raise MyBad # Trigger exception manually.
try:
stuff( ) # Raises exception
except MyBad:
print 'got it' # Handle exception here.
... # Resume execution here.
This time, the raise occurs inside a function, but
it makes no real difference—control jumps back to the
except block immediately. Notice that user-defined
exceptions are caught with try statements just
like built-in exceptions.
24.5.2 Example: Passing Extra Data with raise
As suggested earlier,
raise statements can pass an extra data
item along with the exception for use in a handler. In general,
the extra data allows you to send context
information about the exception to a handler. If
you're writing a data file parser, for example, you
might raise a syntax error exception on errors, and also pass along
an object that gives line and file information to the handler
(we'll meet an example of such later in this part).
Strictly speaking, every exception has the extra data: much like
function return values, it defaults to the special
None object if nothing was passed explicitly. The
following code, raisedata.py, illustrates this
concept at work:
myException = 'Error' # String object
def raiser1( ):
raise myException, "hello" # Raise, pass data.
def raiser2( ):
raise myException # Raise, None implied.
def tryer(func):
try:
func( )
except myException, extraInfo: # Run func; catch exception+data.
print 'got this:', extraInfo
% python
>>> from raisedata import *
>>> tryer(raiser1) # Explicitly passed extra data
got this: hello
>>> tryer(raiser2) # Extra data is None by default.
got this: None
Here, the tryer function always requests the extra
data object; it comes back as an explicit string from
raiser1, but defaults to None
in raiser2's
raise statement. Later, we'll see
that the same hook can be used to access instances raised in
conjunction with class-based exceptions.
24.5.3 Example: Propagating Exceptions with raise
A raise statement without an
exception name or extra data value simply
reraises the current exception. It's typically used
if you need to catch and handle an exception, but
don't want the exception to die in your code:
>>> try:
... raise IndexError, 'spam'
... except IndexError:
... print 'propagating'
... raise
...
propagating
Traceback (most recent call last):
File "<stdin>", line 2, in ?
IndexError: spam
By running a raise this way, the exception will be
reraised and thus propagated to a higher handler, or to the
default
handler at the top, which stops the program with a standard error
message.
|